package com.fruit.service.promotion.impl;

import com.fruit.mapper.promotion.ActivityMapper;
import com.fruit.pojo.promotion.Activity;
import com.fruit.pojo.promotion.ActivityGoods;
import com.fruit.pojo.promotion.ActivityTakeDetail;
import com.fruit.pojo.user.UserInfo;
import com.fruit.service.promotion.Promotion;
import com.fruit.service.user.UserManager;
import com.joe.utils.cluster.ClusterManager;
import com.joe.utils.common.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 活动类
 *
 * @author joe
 * @version 2018.03.17 16:07
 */
@Slf4j
@Service
public class PromotionService implements Promotion {
    @Autowired
    private UserManager userManager;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ClusterManager clusterManager;
    /**
     * 活动缓存表
     */
    private Map<Long, Activity> activityMap;
    /**
     * 统计缓存，key为用户ID，value对应的是redis的set，set中存放的是key对应的用户的购买过的下级ID
     */
    private Map<Integer, Set<Integer>> statistics;
    /**
     * 活动-商品映射表缓存，key是商品ID
     */
    private Map<Long, List<ActivityGoods>> activityGoodsMapper;

    @PostConstruct
    public void init() {
        log.info("初始化活动列表");
        activityMap = clusterManager.getMap(Promotion.ACTIVITY);
        log.info("活动列表为[{}]", activityMap);
        activityGoodsMapper = clusterManager.getMap(Promotion.ACTIVITY_GOODS_MAPPER);
        statistics = new HashMap<>();
    }

    /**
     * 五分钟更新一次缓存
     */
    @Scheduled(initialDelay = 1000 * 60, fixedDelay = 1000 * 60 * 5)
    public void updateCache() {
        updateActivityGoodsMapper();
        updateActivityCache();
    }

    @Override
    public List<ActivityGoods> add(long orderId, int goodsId, int uid) {
        log.info("添加一条促销记录，订单ID：[{}]，商品ID：[{}]，用户ID：[{}]", orderId, goodsId, uid);

        log.info("将该记录插入redis缓存");
        UserInfo userInfo = userManager.getParentOneRights(uid);
        log.info("用户[{}]的上级为：[{}]", uid, userInfo);
        int parentId = userInfo == null ? -1 : userInfo.getId();

        List<ActivityGoods> activityGoodsList = getActivityGoodsFromCache(goodsId, "01", "00");
        log.info("商品[{}]对应的活动列表为：[{}]，将采用第一个", goodsId, activityGoodsList);
        if (activityGoodsList.isEmpty()) {
            log.warn("商品[{}]没有对应的活动！！！", goodsId);
            return Collections.emptyList();
        }

        activityGoodsList.stream().forEach(activityGoods -> {
            if ("00".equals(activityGoods.getType())) {
                if (parentId == -1) {
                    log.info("用户[{}]没有上级", uid);
                    return;
                }
                Activity activity = getActivityFromCache(activityGoods.getActivityId());
                String code = activity.getCode();
                log.info("商品[{}]对应的活动编码为[{}]", goodsId, code);
                log.info("更新缓存");
                updateCache(code, parentId, uid);
                log.info("缓存更新完毕");
            }

            //插入参与活动记录
            ActivityTakeDetail detail = new ActivityTakeDetail();
            detail.setActivityId(activityGoods.getActivityId());
            detail.setOrderId(orderId);
            detail.setGoodsId(goodsId);
            detail.setUserId(uid);
            detail.setSupUserId(parentId);
            detail.setCreateTime(DateUtil.getFormatDate(DateUtil.BASE));
            detail.setUpdateTime(DateUtil.getFormatDate(DateUtil.BASE));
            log.debug("插入参与活动记录[{}]", detail);
            activityMapper.insertActivityTakeDetail(detail);
        });
        return activityGoodsList;
    }

    @Override
    public int getCount(int uid, long id) {
        return getCache(getActivityFromCache(id).getCode(), uid).size();
    }

    @Override
    public int getCount(int uid, String code) {
        return getCache(code, uid).size();
    }

    /**
     * 更新活动参与列表缓存
     *
     * @param code     活动编码
     * @param parentId 父ID
     * @param uid      用户ID
     */
    private void updateCache(String code, int parentId, int uid) {
        log.info("更新活动列表缓存，活动编码为：[{}]，父ID为：[{}]，用户ID为：[{}]", code, parentId, uid);
        Set<Integer> set = getCache(code, parentId);
        set.add(uid);
        log.info("当前用户[{}]的下级参与活动的人数为：[{}]", parentId, set.size());
    }

    /**
     * 从缓存中获取指定活动指定用户对应的参与下级的缓存
     *
     * @param code 活动编码
     * @param uid  用户ID
     * @return 用户对应的参与活动的下级的set集合（集合中存放的是用户ID）
     */
    private Set<Integer> getCache(String code, int uid) {
        log.info("从缓存中获取指定用户[{}]对应的下级参与活动[{}]的列表", uid, code);
        Set<Integer> set = statistics.get(uid);
        if (set == null) {
            statistics.put(uid, clusterManager.getSet(code + uid));
            set = statistics.get(uid);
        }
        log.info("缓存中用户[{}]对应的下级参与活动[{}]的列表为：[{}]", uid, code, set);
        return set;
    }

    /**
     * 从缓存中查找商品ID对应的活动列表（优先读取缓存，缓存中没有读取数据库）
     *
     * @param goodsId 商品ID
     * @param state   要获取活动的状态，0表示所有状态
     * @return 对应的活动列表
     */
    private List<ActivityGoods> getActivityGoodsFromCache(long goodsId, String state, String goodsType) {
        log.info("从缓存查找商品[{}]对应的[{}]状态的活动列表", goodsId, state);
        List<ActivityGoods> activityGoodsList = activityGoodsMapper.get(goodsId);
        if (activityGoodsList == null || activityGoodsList.isEmpty()) {
            activityGoodsList = activityMapper.getActivityGoods(goodsId, "0", goodsType);
            activityGoodsMapper.put(goodsId, activityGoodsList);
        }

        log.info("缓存中查找到的商品[{}]对应的[{}]状态的活动列表为：[{}]", goodsId, state, activityGoodsList);

        if (activityGoodsList != null && !activityGoodsList.isEmpty()) {
            if (state.equals("0")) {
                return activityGoodsList;
            } else {
                return activityGoodsList.stream().filter(activityGoods -> activityGoods.getState().equals(state))
                        .collect(Collectors.toList());
            }
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * 获取活动详情，首先从缓存中获取，如果缓存中没有则从数据库获取
     *
     * @param id 活动ID
     * @return 对应的活动详情
     */
    private Activity getActivityFromCache(long id) {
        log.info("获取ID[{}]对应的活动", id);
        Activity activity = activityMap.get(id);
        log.info("ID[{}]对应的活动为[{}]", id, activity);
        if (activity == null) {
            log.warn("ID[{}]对应的活动在缓存中没有找到，从数据库中查找", id);
            activity = activityMapper.getActivity(id);
            activityMap.putIfAbsent(id, activity);
            activity = activityMap.get(id);
            log.info("ID[{}]对应的活动在数据库中为[{}]", id, activity);
        }
        return activity;
    }

    /**
     * 更新 活动-商品映射表缓存，key是商品ID
     */
    private void updateActivityGoodsMapper() {
        log.info("更新缓存updateActivityGoodsMapper");
        activityGoodsMapper.keySet().parallelStream().forEach(id -> {
            try {
                activityGoodsMapper.put(id, activityMapper.getActivityGoods(id, "0", "00"));
            } catch (Exception e) {
                log.error("updateActivityGoodsMapper更新缓存时出错", e);
            }
        });
        log.info("缓存activityGoodsMapper更新完毕");
    }

    /**
     * 更新活动缓存表
     */
    private void updateActivityCache() {
        log.info("更新缓存activityMap");
        activityMap.keySet().parallelStream().forEach(id -> {
            try {
                activityMap.put(id, activityMapper.getActivity(id));
            } catch (Exception e) {
                log.error("updateActivityCache更新缓存时出错", e);
            }
        });
        log.info("缓存activityMap更新完毕");
    }
}
